package com.tsing.cli.common.config;

import com.tsing.cli.common.exception.CustomException;
import com.tsing.cli.common.exception.ResponseCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * Quartz管理类
 *
 * @author TheTsing
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class QuartzManager {

    private final Scheduler scheduler;

    /**
     * 任务组名
     */
    private static final String JOB_GROUP_NAME = "QUARTZ_JOB_GROUP_NAME";

    /**
     * 触发器组名
     */
    private static final String TRIGGER_GROUP_NAME = "QUARTZ_TRIGGER_GROUP_NAME";

    public void addJob(String jobName, String cron, Class<? extends Job> jobClass, Map<String, Object> params) {
        if (!CronExpression.isValidExpression(cron)) {
            throw new CustomException(ResponseCode.CRON_EXPRESSION);
        }
        JobDetail jobDetail = JobBuilder
                .newJob(jobClass)
                .withIdentity(jobName, JOB_GROUP_NAME)
                .build();
        if (Objects.nonNull(params)) {
            jobDetail.getJobDataMap().putAll(params);
        }
        CronTrigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity(jobName, TRIGGER_GROUP_NAME)
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();
        try {
            scheduler.scheduleJob(jobDetail, trigger);
            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (Exception e) {
            throw new CustomException(ResponseCode.QUARTZ_ALREADY_EXISTS);
        }
        log.info("【 新增定时任务：{} 】", jobName);
    }

    public void deleteJob(String jobName) {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
        try {
            scheduler.pauseTrigger(triggerKey);
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(JobKey.jobKey(jobName, JOB_GROUP_NAME));
        } catch (Exception e) {
            throw new CustomException(ResponseCode.QUARTZ_EXECUTION_ERROR);
        }
        log.info("【 删除定时任务：{} 】", jobName);
    }

    public void deleteJob(List<String> jobNames) {
        for (String jobName : jobNames) {
            deleteJob(jobName);
        }
    }

    /**
     * 只能修改cron
     */
    public void updateJobCron(String jobName, String cron) {
        if (!CronExpression.isValidExpression(cron)) {
            throw new CustomException(ResponseCode.CRON_EXPRESSION);
        }
        TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
        CronTrigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();
        try {
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (Exception e) {
            throw new CustomException(ResponseCode.QUARTZ_EXECUTION_ERROR);
        }
        log.info("【 修改定时任务：{} 】", jobName);
    }

    public List<String> getAllJob() {
        List<String> jobs = new ArrayList<>();
        Set<JobKey> jobKeys;
        try {
            jobKeys = scheduler.getJobKeys(GroupMatcher.anyGroup());
        } catch (Exception e) {
            throw new CustomException(ResponseCode.QUARTZ_EXECUTION_ERROR);
        }
        for (JobKey jobKey : jobKeys) {
            jobs.add(jobKey.getName());
        }
        return jobs;
    }

    public void pauseJob(String jobName) {
        JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
        try {
            scheduler.pauseJob(jobKey);
        } catch (Exception e) {
            throw new CustomException(ResponseCode.QUARTZ_EXECUTION_ERROR);
        }
        log.info("【 暂停定时任务：{} 】", jobName);
    }

    public void resumeJob(String jobName) {
        JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
        try {
            scheduler.resumeJob(jobKey);
        } catch (Exception e) {
            throw new CustomException(ResponseCode.QUARTZ_EXECUTION_ERROR);
        }
        log.info("【 恢复定时任务：{} 】", jobName);
    }

}
